package com.vhall.component.service.rbac.impl;


import cn.hutool.core.util.NumberUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.vhall.component.dao.rbac.RbacMenuMapper;
import com.vhall.component.entity.account.MenuesEntity;
import com.vhall.component.entity.rbac.vo.*;
import com.vhall.component.framework.common.exception.BusinessException;
import com.vhall.component.plugin.common.exception.BizErrorCode;
import com.vhall.component.service.rbac.RbacMenuService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author dalong
 * @date 2021-05-14 14:38
 */
@Service
public class RbacMenuServiceImpl implements RbacMenuService {

    @Autowired
    private RbacMenuMapper menuMapper;

    private MenuesEntity getMenuesById(Integer menuId) {
        LambdaQueryWrapper<MenuesEntity> where = Wrappers.lambdaQuery();
        where.eq(MenuesEntity::getMenuId, menuId)
                .isNull(MenuesEntity::getDeletedAt)
                .last("LIMIT 1");
        return menuMapper.selectOne(where);
    }


    @Override
    public MenuesVO getInfoById(Integer menuId) {
        MenuesVO menuesVO = new MenuesVO();
        MenuesEntity menuesEntity = getMenuesById(menuId);
        if (menuesEntity == null) {
            return null;
        }
        BeanUtils.copyProperties(menuesEntity, menuesVO);
        return menuesVO;
    }

    @Override
    public MenuesVO add(MenuAddReqVO reqVO) {
        Integer pid = Integer.parseInt(reqVO.getPid());
        if (pid > 0) {
            // 查询父菜单
            MenuesVO menuesVO = getInfoById(pid);
            if (menuesVO == null) {
                throw new BusinessException(BizErrorCode.EMPTY_MENU_PARENT);
            }
            reqVO.setType(menuesVO.getType());
        }
        // 查询菜单信息
        List<MenuesEntity> menuEntities = getAllMenuList();
        for (MenuesEntity menuEntity : menuEntities) {
            if (menuEntity.getName().equals(reqVO.getName())) {
                throw new BusinessException(BizErrorCode.BIZ_MENU_NAME_EXIST);
            }
            if (menuEntity.getUrl().equals(reqVO.getUrl())) {
                throw new BusinessException(BizErrorCode.BIZ_MENU_URL_EXIST);
            }
        }
        // create
        MenuesEntity menuEntity = new MenuesEntity();
        BeanUtils.copyProperties(reqVO, menuEntity);
        menuEntity.setSort(reqVO.getSort() == null ? 0 : reqVO.getSort());
        menuEntity.setPid(pid);
        menuEntity.setType(reqVO.getType());
        menuEntity.setUpdatedAt(LocalDateTime.now());
        menuEntity.setCreatedAt(LocalDateTime.now());
        menuMapper.insert(menuEntity);
        menuEntity.setMenuId(menuEntity.getMenuId());
        MenuesVO menuesVO = new MenuesVO();
        BeanUtils.copyProperties(menuEntity, menuesVO);
        return menuesVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<Integer> batchDelete(MenuDeleteReqVO reqVO) {
        List<Integer> returnMenuList = new ArrayList<>();
        String[] menuIdList = reqVO.getMenuIds().split(",");
        for (String menuId : menuIdList) {
            LambdaUpdateWrapper<MenuesEntity> updateWrapper = Wrappers.lambdaUpdate();
            updateWrapper.eq(MenuesEntity::getMenuId, menuId)
                    .set(MenuesEntity::getDeletedAt, LocalDateTime.now())
                    .set(MenuesEntity::getStatus, -1);
            if (!NumberUtil.isInteger(menuId) || menuMapper.selectById(menuId) == null) {
                throw new BusinessException(BizErrorCode.EMPTY_MENU);
            }
            if (menuMapper.update(null, updateWrapper) > 0) {
                returnMenuList.add(Integer.valueOf(menuId));
            }
        }
        return returnMenuList;
    }

    @Override
    public boolean edit(MenuEditReqVO reqVO) {
        MenuesEntity menuEntity = getMenuesById(reqVO.getMenuId());
        if (menuEntity == null) {
            throw new BusinessException(BizErrorCode.EMPTY_MENU);
        }

        // 查询菜单信息
        List<MenuesEntity> menuEntities = getAllMenuList();
        for (MenuesEntity menuEntityTmp : menuEntities) {
            if (menuEntityTmp.getUrl().equals(reqVO.getUrl()) && !menuEntityTmp.getMenuId().equals(reqVO.getMenuId())) {
                throw new BusinessException(BizErrorCode.BIZ_MENU_URL_EXIST);
            }
            if (menuEntityTmp.getName().equals(reqVO.getName()) && !menuEntityTmp.getMenuId().equals(reqVO.getMenuId())) {
                throw new BusinessException(BizErrorCode.BIZ_MENU_NAME_EXIST);
            }
        }

        // 检测是否已存在相同记录
        LambdaQueryWrapper<MenuesEntity> where = Wrappers.lambdaQuery();
        where.eq(MenuesEntity::getName, reqVO.getName())
                .isNull(MenuesEntity::getDeletedAt)
                .last("LIMIT 1");
        if (StringUtils.isNotEmpty(reqVO.getUrl())) {
            where.eq(MenuesEntity::getUrl, reqVO.getUrl());
        }
        if (StringUtils.isNotEmpty(reqVO.getPid())) {
            where.eq(MenuesEntity::getPid, reqVO.getPid());
        }
        MenuesEntity otherMenuEntity = menuMapper.selectOne(where);
        if (otherMenuEntity != null && !otherMenuEntity.getMenuId().equals(reqVO.getMenuId())) {
            throw new BusinessException(BizErrorCode.BIZ_MENU_EXIST);
        }
        // update
        BeanUtils.copyProperties(reqVO, menuEntity);
        menuEntity.setSort(reqVO.getSort() == null ? null : reqVO.getSort());
        menuEntity.setPid(reqVO.getPid() == null ? null : Integer.parseInt(reqVO.getPid()));
        menuEntity.setType(reqVO.getType() == null ? null : reqVO.getType());
        menuEntity.setCreatedAt(LocalDateTime.now());
        menuEntity.setUpdatedAt(LocalDateTime.now());
        return menuMapper.updateById(menuEntity) > 0;
    }

    @Override
    public boolean updateSortOrStatus(MenuEditReqVO reqVO) {
        MenuesEntity menuEntity = getMenuesById(reqVO.getMenuId());
        if (menuEntity == null) {
            throw new BusinessException(BizErrorCode.EMPTY_MENU);
        }
        if (reqVO.getSort() != null) {
            menuEntity.setSort(reqVO.getSort());
        }
        if (reqVO.getStatus() != null) {
            menuEntity.setStatus(reqVO.getStatus());
            if (reqVO.getStatus() == -1) {
                menuEntity.setDeletedAt(LocalDateTime.now());
            }
        }
        menuEntity.setUpdatedAt(LocalDateTime.now());
        return menuMapper.updateById(menuEntity) > 0;
    }

    @Override
    public List getList(MenuListReqVO reqVO) {
        List<MenuesEntity> menuesEntities = menuMapper.selectList(Wrappers.<MenuesEntity>lambdaQuery()
                .isNull(MenuesEntity::getDeletedAt));
        if (reqVO.getTree() == null || "0".equalsIgnoreCase(reqVO.getTree())) {
            return menuesEntities;
        }
        List<MenuListRspVO> vos = menuesEntities.stream().map(x ->
        {
            MenuListRspVO me = new MenuListRspVO<>();
            BeanUtils.copyProperties(x, me);
            return me;
        }).collect(Collectors.toList());

        // format data
        List<MenuListRspVO> result = new ArrayList<>();
        for (MenuListRspVO menuListRspVO : vos) {
            if (menuListRspVO.getPid() == 0) {
                List<MenuListRspVO> treeList = getTreeList(vos, menuListRspVO.getMenuId());
                menuListRspVO.setChildren(treeList);
                result.add(menuListRspVO);
            }
        }
        return result;
    }

    /**
     * 获取每个子模块
     *
     * @param
     * @return
     */
    private List<MenuListRspVO> getTreeList(List<MenuListRspVO> lists, Integer pid) {
        List<MenuListRspVO> result = new ArrayList<>();
        lists.forEach(menuListRspVO -> {
            if (pid.equals(menuListRspVO.getPid())) {
                List<MenuListRspVO> child = getTreeList(lists, menuListRspVO.getMenuId());
                menuListRspVO.setChildren(child);
                result.add(menuListRspVO);
            }
        });
        return result;
    }

    /**
     * 查询所有菜单数据
     *
     * @return
     */
    private List<MenuesEntity> getAllMenuList() {
        LambdaQueryWrapper<MenuesEntity> wrapper = Wrappers.lambdaQuery();
        wrapper.isNull(MenuesEntity::getDeletedAt);
        return menuMapper.selectList(wrapper);
    }

}
